/*
 * Copyright (c) 2018 - 2028. www.vtuzx.com Inc. All Rights Reserved
 */
package com.vtuzx.kingdee.xqc_api.service.impl;

import com.mongodb.client.result.UpdateResult;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.bean.dto.VtuzxPage;
import com.vtuzx.core.bean.dto.VtuzxToken;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.file.excel.VtuzxExcel;
import com.vtuzx.core.file.excel.VtuzxExcelCell;
import com.vtuzx.core.file.excel.VtuzxExcelRow;
import com.vtuzx.core.file.excel.VtuzxExcelSheet;
import com.vtuzx.core.utils.VtuzxUtil;
import com.vtuzx.fast.utils.FastUtil;
import com.vtuzx.kingdee.xqc_api.service.*;
import com.vtuzx.kingdee.xqc_core.bean.VtuzxArrayList;
import com.vtuzx.kingdee.xqc_core.constant.BillEvent;
import com.vtuzx.kingdee.xqc_core.constant.BillStatus;
import com.vtuzx.kingdee.xqc_core.constant.BillType;
import com.vtuzx.kingdee.xqc_core.constant.IXqcConst;
import com.vtuzx.kingdee.xqc_core.dao.*;
import com.vtuzx.kingdee.xqc_core.service.IJiKeYunApiService;
import com.vtuzx.web.bean.VtuzxDownloadBean;
import com.vtuzx.web.dao.mongo.CustomerDao;
import org.apache.http.client.utils.DateUtils;
import org.apache.poi.ss.usermodel.DateUtil;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 采购服务
 */
@Service
public class XqcOtherOutServiceImpl implements IXqcOtherOutService {

    /** Logger */
    private static final Logger _logger = LoggerFactory.getLogger(XqcOtherOutServiceImpl.class);

    @Autowired
    private OtherOutDao otherOutDao;

    @Autowired
    private SyncOrderDao syncOrderDao;

    @Autowired
    private OtherOutDetailDao otherOutDetailDao;

    @Autowired
    private OtherOutDetailBoxDao otherOutDetailBoxDao;

    @Autowired
    private IXqcInventoryService inventoryService;

    @Autowired
    private InventoryDetailDao inventoryDetailDao;

    @Autowired
    private MaterialDao materialDao;

    @Autowired
    private XqcInventoryServiceImpl xqcInventoryService;

    @Autowired
    private IXqcSyncKingdeeOrderService syncKingdeeOrderService;

    @Autowired
    private StoreTokenDao storeTokenDao;

    @Autowired
    private IJiKeYunApiService iJiKeYunApiService;

    @Autowired
    private StockDao stockDao;


    @Override
    public VtuzxMap saveUserOtherOut(ObjectId _userId, String userName, Map<String, Object> param) throws VtuzxException {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String remark = VtuzxUtil.getString(param, "remark");
        String billNo = IXqcConst.createBillNo(BillType.QTCK);
        String type = VtuzxUtil.getString(param,"type");
        List<String> boxNoList = new ArrayList<>();
        List<String> materialRowIdList = new ArrayList<>();
        List<ObjectId> detailIdList = new ArrayList<>();
        Criteria opCond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        Iterator<Document> detailItr = otherOutDetailDao.findList(opCond, null, 0, 0);
        int boxCount = 0;
        double count = 0d;
        while(detailItr.hasNext()) {
            Document detail = detailItr.next();
            ObjectId id = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            boxCount += VtuzxUtil.getDouble(detail, "boxCount");
            count += VtuzxUtil.getDouble(detail, "count");
            detailIdList.add(id);
        }

        VtuzxMap boxIdMap = new VtuzxMap();
        Iterator<Document> boxItr = otherOutDetailBoxDao.findList(Criteria.where("_detailId").in(detailIdList), null, 0, 0);
        while (boxItr.hasNext()) {
            Document boxDoc = boxItr.next();
            String boxNo = VtuzxUtil.getString(boxDoc, "boxNo");
            String id = VtuzxUtil.getString(boxDoc, "_detailId");
            boxNoList.add(boxNo);
            boxIdMap.append(boxNo, id);
        }

        List<String> outBoxNoList = new ArrayList<>();
        Iterator<Document> inventoryItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(boxNoList).and("status").is("in"), null, 0, 0);
        while (inventoryItr.hasNext()) {
            Document inventoryDoc = inventoryItr.next();
            String status = VtuzxUtil.getString(inventoryDoc, "status");
            String boxNo = VtuzxUtil.getString(inventoryDoc, "boxNo");
            if ("out".equals(status)) {
                outBoxNoList.add(boxNo);
                String detailId = VtuzxUtil.getString(boxIdMap, boxNo);
                materialRowIdList.add(detailId);
            }
        }
        if (outBoxNoList.size() > 0) {
            return new VtuzxMap("outBoxNo", outBoxNoList).append("idList", materialRowIdList);
        }


        Document otherOutDoc = new Document("billNo", billNo)
                .append("stockNo", stockNo)
                .append("boxCount", boxCount)
                .append("count", count)
                .append("remark", remark)
                .append("type",type)//新增出库类型
                .append("isPrint","unSeal")//是否打印
                .append("status", BillStatus.Save.toString());
        otherOutDao.insertBill(_userId, userName, otherOutDoc);
        try {
            Document detailUpdateVal = new Document("$set", new Document("billNo", billNo));
            detailUpdateVal.append("$unset", new Document("isTemp", 1));
            otherOutDetailDao.updateManyRedirect(opCond, detailUpdateVal);
            otherOutDetailBoxDao.updateManyRedirect(opCond, detailUpdateVal);
        } catch(Exception e) {
            Criteria rollbackCond = Criteria.where("billNo").is(billNo);
            otherOutDao.deleteOne(rollbackCond);
            otherOutDetailDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            otherOutDetailBoxDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            throw e;
        }
        return new VtuzxMap("outBoxNo", outBoxNoList).append("billNo", billNo);
    }

    /**
     * 判断当前日期是否是本月的
     * @param startTime
     * @return
     */
    private boolean compareDate(Date startTime){
        LocalDate currentDate = LocalDate.now();
        int currentMonth = currentDate.getMonthValue();//当前月份
        int currentYear = currentDate.getYear();
        Instant instant = startTime.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDate startDate = instant.atZone(zoneId).toLocalDate();
        int monthValue = startDate.getMonthValue();//单据月份
        int yearValue = startDate.getYear();
        if (currentMonth == monthValue && currentYear == yearValue){
            return true;
        } else {
            return false;
        }
    }

    /**
     * 生产领料审批
     *
     * @param _userId 用户ID
     * @param userName 用户名
     * @param stockNo 仓库编码
     * @param billNo 单据号
     * @throws VtuzxException 异常处理
     */
    @Override
    public void auditOtherOutOrder(ObjectId _userId, String userName, String stockNo, String billNo) throws VtuzxException {
        Criteria getCond = Criteria.where("billNo").is(billNo);
        Document otherOutDoc = otherOutDao.findOne(Criteria.where("billNo").is(billNo));
        //单据审核时间不允许跨月
        Date createTime = VtuzxUtil.getObject(otherOutDoc, "createTime");
        boolean res = compareDate(createTime);//判断是否是当月的
        if(!res){
            throw new VtuzxException("单据已经跨月不允许审核,请重新添加单据");
        }
        Iterator<Document> otherOutDetailBoxItr = otherOutDetailBoxDao.findList(getCond, null, 0, 0);
        List<String> boxNoList = new ArrayList<>();
        List<VtuzxMap> bcBoxList = new ArrayList<>();
        List<Document> zsBoxList = new ArrayList<>();
        while(otherOutDetailBoxItr.hasNext()) {
            Document doc = otherOutDetailBoxItr.next();
            String barcodeType = VtuzxUtil.getString(doc, "barcodeType");
            boolean isZS = VtuzxUtil.getBoolean(doc, "isZS");
            String traceBack = VtuzxUtil.getString(doc, "traceBack");
            String boxNo = VtuzxUtil.getString(doc, "boxNo");
            if ("BC".equals(barcodeType)) {
                bcBoxList.add(new VtuzxMap("boxNo", boxNo).append("count", BigDecimal.valueOf(VtuzxUtil.getDouble(doc, "count")).setScale(2, RoundingMode.HALF_UP).doubleValue())
                        .append("locationNo", VtuzxUtil.getString(doc, "locationNo")));
            } else {
                if (isZS) {
                    zsBoxList.add(new Document("traceBack", traceBack).append("boxNo", boxNo));
                } else {
                    boxNoList.add(VtuzxUtil.getString(doc, "boxNo"));
                }
            }
        }
        //判断一下箱号是否出库(存在单据创建很久才出库的情况)
//        if (!VtuzxUtil.isEmpty(boxNoList)){
//            Iterator<Document> inventorItr = inventoryDetailDao.findList(Criteria.where("boxNo").in(boxNoList),null,0,0);
//            while (inventorItr.hasNext()){
//                Document inventoryDoc = inventorItr.next();
//                String status = VtuzxUtil.getString(inventoryDoc,"status");
//                String boxNo = VtuzxUtil.getString(inventoryDoc,"boxNo");
//                if ("out".equals(status)){
//                    throw new VtuzxException(String.format("箱号:%s已经出库",boxNo));
//                }
//            }
//        }
        otherOutDao.audit(_userId, userName, billNo);
        Document otherDoc = otherOutDao.findOne(Criteria.where("billNo").is(billNo));
        String type = VtuzxUtil.getString(otherDoc,"type");
        if (!"沫沫".equals(type) && !"合-拆箱".equals(type)){//沫沫类型不传
            try {
                syncKingdeeOrderService.syncOtherOutOrder(_userId, userName, billNo, "pda");
            } catch (Exception e) {
                _logger.info(e.getMessage());
            }
        }

        // 更新即时库存
        try {
            inventoryService.reduceInventory(_userId, userName, BillEvent.Audit, BillType.QTCK, stockNo, billNo, boxNoList, bcBoxList, zsBoxList);
        } catch(Exception e) {
            otherOutDao.unaudit(billNo);
            throw e;
        }
        //传极客云出库单

        if ("包材出库".equals(type)){
            List<Document> otherList = new ArrayList<>();
            Iterator<Document> otherOutItr = otherOutDetailBoxDao.findList(Criteria.where("billNo").is(billNo),null,0,0);
            while (otherOutItr.hasNext()){
                Document otherOutDetailDoc = otherOutItr.next();
                otherList.add(otherOutDetailDoc);
            }
            if (!VtuzxUtil.isEmpty(otherList)){//有符合条件的物料需要传
                Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
                String outWarehouseCode = "XQWG00101";//仓库编码
                VtuzxMap stockParam = new VtuzxMap();//入库参数
                List<VtuzxMap> stockOutDetailViews = new ArrayList<>();//出库申请单明细
                for (Document doc : otherList){//循环添加货品明细信息
                    String materialNo = VtuzxUtil.getString(doc,"materialNo");
                    String unit = VtuzxUtil.getString(doc,"unit");
                    double count = VtuzxUtil.getDouble(doc,"count");
                    VtuzxMap goodsMap = new VtuzxMap();//getGoodsList方法返回值
                    //需要先获取条码(skubarcode)
                    VtuzxMap goodsParam = new VtuzxMap();
                    goodsParam.append("pageIndex", 0)
                            .append("pageSize", 1)
                            .append("goodsNo", materialNo);
                    try {
                        goodsMap = iJiKeYunApiService.getGoodsList(storeDoc, goodsParam);
                    } catch (Exception e) {
                        throw new VtuzxException(e.getMessage());
                    }
                    LinkedHashMap result = VtuzxUtil.getObject(goodsMap, "result");
                    LinkedHashMap data = VtuzxUtil.getObject((Map<String, Object>) result, "data");
                    List<LinkedHashMap> goods = VtuzxUtil.getObject((Map<String, Object>) data, "goods");
                    LinkedHashMap goodsResult = goods.get(0);
                    String skuBarcode = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuBarcode");

                    VtuzxMap map = new VtuzxMap();
                    map.append("skuBarcode",skuBarcode)
                            .append("skuCount",count)
                            .append("unitName",unit)
                            .append("isCertified",1)
                            .append("relDetailId",billNo);
                    stockOutDetailViews.add(map);
                }
                stockParam.append("outWarehouseCode",outWarehouseCode)
                        .append("outType", 204)
                        .append("relDataId", billNo)//关联单据编号,可随机，保证不重复即可
                        .append("applyDate", VtuzxUtil.formatYmdHmsF(new Date()))
                        .append("operator", userName)
                        .append("source", "OPEN")
                        .append("currencyRate",1)
                        .append("memo","包材出库")
                        .append("stockOutDetailViews", stockOutDetailViews);

                //创建出库单
                try {
                    iJiKeYunApiService.createStockOut(storeDoc, stockParam);
                } catch (Exception e) {
                    _logger.info(e.getMessage());
                    throw new VtuzxException(e.getMessage());
                }
            }
        }
    }


    @Override
    public Object addUserOtherOutMaterialBoxList(ObjectId _userId, String name, String stockNo, List<Map<String, Object>> boxList, String billNo) throws VtuzxException {
        List<VtuzxMap> boxNoDateList = new ArrayList<>();
        List<String> boxNoList = new ArrayList<>();
        for (Map<String, Object> box: boxList) {
            boxNoList.add(VtuzxUtil.getString(box, "boxNo"));
        }
        Iterator<Document> scanBoxDocItr = otherOutDetailBoxDao.findList(Criteria.where("boxNo").in(boxNoList).and("isTemp").is(true), null, 0, 0);
        while (scanBoxDocItr.hasNext()) {
            Document scanDoc = scanBoxDocItr.next();
            String boxNo = VtuzxUtil.getString(scanDoc, "boxNo");
            String createUserName = VtuzxUtil.getString(scanDoc, "createUserName");
            boxNoDateList.add(new VtuzxMap(boxNo, createUserName));
        }
        if (boxNoDateList.size() != 0) {
            throw new VtuzxException("托盘中箱号已添加，请删除后重新扫描!【" + boxNoDateList.toString() + "】");
        }

        for(Map<String, Object> box: boxList) {
            String boxNo = VtuzxUtil.getString(box, "boxNo");
            String locationNo = VtuzxUtil.getString(box, "locationNo");
            String traceBack = VtuzxUtil.getString(box, "traceBack");
            boolean isZS = VtuzxUtil.getBoolean(box, "isZS");
            double count = VtuzxUtil.getDouble(box, "count");
            try{
                VtuzxMap xqcProduceDetail = xqcInventoryService.getMaterialBox(stockNo, locationNo, boxNo);
                List<VtuzxMap> dataList = VtuzxUtil.getObject(xqcProduceDetail, "data");
                for (VtuzxMap data: dataList) {
                    addUserOtherOutMaterialBoxInner(data, _userId, name, stockNo, boxNo, count, billNo, isZS, traceBack);
                }
            } catch (Exception e) {
//                _logger.info("addUserOtherOutMaterialBoxList error:" + e.getMessage());
                throw new VtuzxException(e.getMessage());
            }
        }
        return null;
    }

    @Override
    public VtuzxMap addUserOtherOutMaterialBox(ObjectId _userId, String userName, String stockNo, String boxNo, int count) throws VtuzxException {
        VtuzxMap xqcProduceDetail = xqcInventoryService.getMaterialBox(stockNo, boxNo);
        ObjectId _detailId = addUserOtherOutMaterialBoxInner(xqcProduceDetail, _userId, userName, stockNo, boxNo, count, "", false, "");
        Document otherOutDetailDoc = otherOutDetailDao.findById(_detailId);
        return new VtuzxMap("boxCount", VtuzxUtil.getObject(otherOutDetailDoc, "boxCount"))
                .append("count", VtuzxUtil.getObject(otherOutDetailDoc, "count"));

    }

    /**
     * 其他出库增加临时箱号内部方法
     * @param xqcProduceDetail 收货单详细
     * @param _userId 用户ID
     * @param userName 用户名
     * @param stockNo 仓库编码
     * @param boxNoKey 箱号
     * @return 信息ID
     * @throws VtuzxException 异常处理
     */
    private ObjectId addUserOtherOutMaterialBoxInner(VtuzxMap xqcProduceDetail, ObjectId _userId, String userName, String stockNo, String boxNoKey, double inputCount, String billNo, boolean isZS, String traceBack) throws VtuzxException {
        String barcodeType = VtuzxUtil.getString(xqcProduceDetail, "barcodeType");
        String materialNo = VtuzxUtil.getString(xqcProduceDetail, "materialNo");
        double count = inputCount;
        String boxNo;
        if ("BC".equals(barcodeType)) {
            String[] boxValues = boxNoKey.split("\\|\\;");
            if (boxValues.length == 5) {
                boxNo = boxNoKey;
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
                boxNo = boxNo + "|;batch";
            } else {
                boxNo = boxNoKey;
            }
        } else {
            boxNo = boxNoKey;
            count = VtuzxUtil.getDouble(xqcProduceDetail, "count");
//            Document scanBoxDoc = otherOutDetailBoxDao.findOne(Criteria.where("boxNo").is(boxNo));
//            if (scanBoxDoc != null) {
//                throw new VtuzxException("箱号已领料!");
//            }
        }
        Criteria pickCond = new Criteria("boxNo").is(boxNo).and("isTemp").is(true);
        if (isZS) {
            pickCond.and("traceBack").is(traceBack);
        }
        Document scanBoxDoc = otherOutDetailBoxDao.findOne(pickCond);
        if (scanBoxDoc != null) {
            throw new VtuzxException("箱号已领料，请勿重复添加!");
        }
        String materialNumber = VtuzxUtil.getString(xqcProduceDetail, "materialNo");
        String materialName = VtuzxUtil.getString(xqcProduceDetail, "materialName");
        String materialSpec = VtuzxUtil.getString(xqcProduceDetail, "materialSpec");
        String batchNo = VtuzxUtil.getString(xqcProduceDetail, "batchNo");
        String unit = VtuzxUtil.getString(xqcProduceDetail, "unit");
        String produceDate = VtuzxUtil.getString(xqcProduceDetail, "produceDate");
        double exp = VtuzxUtil.getDouble(xqcProduceDetail, "exp");
        String inStockTime = VtuzxUtil.getString(xqcProduceDetail, "inStockTime");
        String locationNo = VtuzxUtil.getString(xqcProduceDetail, "locationNo");
        Criteria detailCond = Criteria.where("_createUserId").is(_userId);
        if (!VtuzxUtil.isEmpty(billNo)) {
            detailCond.and("status").is("save");
        } else {
            detailCond.and("isTemp").is(true);
        }
        detailCond.and("stockNo").is(stockNo);
        detailCond.and("materialNo").is(materialNo);
        detailCond.and("batchNo").is(batchNo);
        detailCond.and("unit").is(unit);
        Document detail = otherOutDetailDao.findOne(detailCond);
        Document updateVal = new Document();

        if (detail == null) {
            if (!VtuzxUtil.isEmpty(billNo)) {
                updateVal.append("status", "save");
                updateVal.append("billNo", billNo);
            } else {
                updateVal.append("isTemp", true);
            }
            updateVal.append("stockNo", stockNo);
            updateVal.append("materialNo", materialNumber);
            updateVal.append("materialName", materialName);
            updateVal.append("materialSpec", materialSpec);
            updateVal.append("batchNo", batchNo);
            updateVal.append("unit", unit);
            updateVal.append("_createUserId", _userId);
            updateVal.append("createUserName", userName);
            updateVal.append("boxCount", 1);
            if (isZS) {
                Document inventoryDoc = inventoryDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
                double traceCount = VtuzxUtil.getDouble(inventoryDoc,"traceCount");
                if (!VtuzxUtil.isEmpty(traceCount) && traceCount != 0.0){
                    updateVal.append("count", traceCount);
                } else {
                    updateVal.append("count", 1);
                }

            } else {
                updateVal.append("count", count);
            }
            updateVal.append("produceDate", produceDate);
            updateVal.append("exp", exp);
            updateVal.append("inStockTime", inStockTime);
        } else {
            if (isZS) {
                updateVal = new Document("$inc", new Document("boxCount", 1).append("count", 1));
            } else {
                updateVal = new Document("$inc", new Document("boxCount", 1).append("count", count));
            }
        }
        ObjectId _detailId;
        if (detail == null) {
            _detailId = otherOutDetailDao.insertOne(updateVal);
        } else {
            _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            otherOutDetailDao.updateByIdRedirect(_detailId, updateVal);
        }
        Document detailBox = new Document();
        if (!VtuzxUtil.isEmpty(billNo)) {
            detailBox.append("status", "save");
            detailBox.append("billNo", billNo);
        } else {
            detailBox.append("isTemp", true);
        }
        detailBox.append("_detailId", _detailId);
        detailBox.append("boxNo", boxNo);
        detailBox.append("barcodeType", barcodeType);
        if (isZS) {
            detailBox.append("traceBack", traceBack);
            detailBox.append("isZS", true);
            detailBox.append("count", 1);
        } else {
            detailBox.append("count", count);
        }
        detailBox.append("_createUserId", _userId);
        detailBox.append("createUserName", userName);
        detailBox.append("stockNo", stockNo);
        detailBox.append("unit", unit);
        detailBox.append("locationNo", locationNo);
        detailBox.append("materialNo", materialNo);
        otherOutDetailBoxDao.insertOne(detailBox);
        return _detailId;
    }

    @Override
    public VtuzxMap deleteUserOtherOutMaterialBox(ObjectId _userId, String id) {
        Document otherOutDetailBoxDoc = otherOutDetailBoxDao.findOne(Criteria.where("_detailId").is(FastUtil.convertId(id)));
        ObjectId _detailId = VtuzxUtil.getObject(otherOutDetailBoxDoc, "_detailId");
        String billNo = VtuzxUtil.getString(otherOutDetailBoxDoc, "billNo");
        if (!VtuzxUtil.isEmpty(billNo)) {
            double count = VtuzxUtil.getDouble(otherOutDetailBoxDoc, "count");
            otherOutDao.updateOneRedirect(Criteria.where("billNo").is(billNo), new Document("$inc", new Document("count", -count).append("boxCount", -1)));
        }
        otherOutDetailBoxDao.deleteById(FastUtil.convertId(id));
        Iterator<Document> otherOutDetailBoxItr = otherOutDetailBoxDao.findList(Criteria.where("_detailId").is(_detailId), null, 0, 0);
        int boxCount = 0;
        double total = 0;
        while(otherOutDetailBoxItr.hasNext()) {
            Document doc = otherOutDetailBoxItr.next();
            double otherOutDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = otherOutDetailBoxCount + total;
            boxCount++;
        }
        if (boxCount == 0 && total == 0) {
            otherOutDetailDao.deleteById(_detailId);
        } else {
            otherOutDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        }
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public void deleteUserOtherOutMaterial(ObjectId _userId, String id) {
        Document detailDoc = otherOutDetailDao.findById(id);
        String billNo = VtuzxUtil.getString(detailDoc, "billNo");
        if (!VtuzxUtil.isEmpty(billNo)) {
            double count = VtuzxUtil.getDouble(detailDoc, "count");
            int boxCount = VtuzxUtil.getInt(detailDoc, "boxCount");
            otherOutDao.updateOneRedirect(Criteria.where("_id").is(FastUtil.convertId(id)), new Document("$inc", new Document("count", -count).append("boxCount", -boxCount)));
        }
        otherOutDetailDao.deleteById(FastUtil.convertId(id));
        otherOutDetailBoxDao.deleteMany(Criteria.where("_detailId").is(FastUtil.convertId(id)));
    }

    @Override
    public void deleteUserOtherOut(ObjectId _userId, String stockNo) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        otherOutDetailDao.deleteMany(cond);
        otherOutDetailBoxDao.deleteMany(cond);
    }

    @Override
    public VtuzxMap updateUserOtherOutMaterialBox(ObjectId _userId, String stockNo, String materialNo, String boxNo, double count) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("boxNo").is(boxNo).and("isTemp").is(true);
        Document detailBoxDoc = otherOutDetailBoxDao.findOne(cond);
        ObjectId _detailId = VtuzxUtil.getObject(detailBoxDoc, "_detailId");
        otherOutDetailBoxDao.updateOne(cond, new Document("count", count));
        Iterator<Document> otherOutDetailBoxItr = otherOutDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true), new Document("stockNo", 1), 0, 0);
        int boxCount = 0;
        double total = 0;
        while(otherOutDetailBoxItr.hasNext()) {
            Document doc = otherOutDetailBoxItr.next();
            double otherOutDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = otherOutDetailBoxCount + total;
            boxCount++;
        }
        otherOutDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public VtuzxMap getUserOtherOutMaterial(ObjectId _userId, String stockNo, String billNo) {
        List<VtuzxMap> otherOutDetailList = new ArrayList<>();
        Document header = new Document();
        Criteria cond = new Criteria();
        if (VtuzxUtil.isEmpty(billNo)) {
            cond.and("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        } else {
            cond.and("billNo").is(billNo);
            header = otherOutDao.findOne(Criteria.where("billNo").is(billNo));
        }
        Iterator<Document> otherOutDetailItr = otherOutDetailDao.findList(cond, null, 0, 0);
        while (otherOutDetailItr.hasNext()) {
            Document otherOutDetailDoc = otherOutDetailItr.next();
            VtuzxMap otherOutDetailMap = new VtuzxMap(otherOutDetailDoc);
            String id = VtuzxUtil.removeString(otherOutDetailMap, IVtuzxConst.Key__id);
            String createUserId = VtuzxUtil.removeString(otherOutDetailMap, "_createUserId");
            otherOutDetailMap.append("id", id).append("createUserId", createUserId);
            otherOutDetailList.add(otherOutDetailMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, otherOutDetailList).append("header", header);
    }

    @Override
    public VtuzxMap getUserOtherOutMaterialBox(ObjectId _userId, String _detailId) {
        List<VtuzxMap> otherOutDetailBoxList = new ArrayList<>();
        Iterator<Document> otherOutDetailBoxItr = otherOutDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("_detailId").is(new ObjectId(_detailId)), null, 0, 0);
        while (otherOutDetailBoxItr.hasNext()) {
            Document otherOutDetailBoxDoc = otherOutDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(otherOutDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            otherOutDetailBoxList.add(boxMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, otherOutDetailBoxList);
    }

    @Override
    public VtuzxMap getOtherOutBill(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String type = VtuzxUtil.getString(param,"type");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String isPrint = VtuzxUtil.getString(param, "isPrint");
        String taskBillNo = VtuzxUtil.getString(param, "taskBillNo");
        List<String> auditTime = VtuzxUtil.getObject(param, "auditTime");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        Criteria cond = new Criteria("apply").ne(true);
        cond.and("count").ne(0);//数量等于零的不显示
        List<VtuzxMap> dataList = new ArrayList<>();
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").regex(type);
        }
        if (!VtuzxUtil.isEmpty(taskBillNo)) {
            cond.and("taskBillNo").regex(taskBillNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(isPrint)) {
            cond.and("isPrint").is(isPrint);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(auditTime)) {
            cond.and("auditTime").gte(VtuzxUtil.parseDate(auditTime.get(0))).lte(VtuzxUtil.parseDate(auditTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo) || !VtuzxUtil.isEmpty(boxNo)) {
            List<String> inBillNoList = new ArrayList<>();
            if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo)) {
                Criteria smallCond = new Criteria();
                if (!VtuzxUtil.isEmpty(materialNo)) {
                    smallCond.and("materialNo").is(materialNo);
                }
                if (!VtuzxUtil.isEmpty(batchNo)) {
                    smallCond.and("batchNo").regex(batchNo);
                }
                Iterator<Document> purInDetailItr = otherOutDetailDao.findList(smallCond, new Document("createTime",-1), 0, 0);
                while (purInDetailItr.hasNext()) {
                    Document purInDetailDoc = purInDetailItr.next();
                    String purInBillNo = VtuzxUtil.getString(purInDetailDoc, "billNo");
                    inBillNoList.add(purInBillNo);
                }
            } else {
                Iterator<Document> boxItr = otherOutDetailBoxDao.findList(Criteria.where("boxNo").is(boxNo), new Document("createTime",-1), 0, 0);
                while (boxItr.hasNext()) {
                    Document boxDoc = boxItr.next();
                    inBillNoList.add(VtuzxUtil.getString(boxDoc, "billNo"));
                }
            }

            Iterator<Document> purInItr = otherOutDao.findList(Criteria.where("billNo").in(inBillNoList),  new Document("createTime",-1), 0, 0);
            while (purInItr.hasNext()) {
                Document purInDoc = purInItr.next();
                VtuzxMap purInMap = new VtuzxMap(purInDoc);
                purInMap.append("id", VtuzxUtil.removeString(purInMap, IVtuzxConst.Key__id));
                purInMap.append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(purInMap, "createTime")));
                dataList.add(purInMap);
            }
            return new VtuzxMap(IVtuzxConst.Key_data, dataList);
        }
        VtuzxPage page = otherOutDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("remark", VtuzxUtil.getString(doc, "remark"))
                .append("taskBillNo",VtuzxUtil.getString(doc,"taskBillNo"))
                .append("type",VtuzxUtil.getString(doc,"type"))
                .append("isPrint",VtuzxUtil.getString(doc,"isPrint"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "createTime")))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherOutBillDetail(ObjectId _userId, String stockNo, String billNo) {
        Document otherOutDoc = otherOutDao.findOne(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo));
        String ckBillNo = VtuzxUtil.getString(otherOutDoc, "billNo");
        String remark = VtuzxUtil.getString(otherOutDoc,"remark");
        String createUserName = VtuzxUtil.getString(otherOutDoc, "createUserName");
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(otherOutDoc, "createTime"));
        String stock = VtuzxUtil.getString(otherOutDoc, "stockNo");
        String type = VtuzxUtil.getString(otherOutDoc, "type");//出库类型
        double count = VtuzxUtil.getDouble(otherOutDoc, "count");
        int boxCount = VtuzxUtil.getInt(otherOutDoc, "boxCount");
        VtuzxMap header = new VtuzxMap("billNo", ckBillNo)
                .append("createUserName", createUserName)
                .append("createTime", createTime)
                .append("stockNo", stock)
                .append("type", type)
                .append("count", String.format("%.2f",count))
                .append("remark",remark)
                .append("boxCount", boxCount);

        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> otherOutDetailItr = otherOutDetailDao.findList(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo), null, 0, 0);
        while (otherOutDetailItr.hasNext()) {
            Document otherOutDetailDoc = otherOutDetailItr.next();
            VtuzxMap otherOutDetailMap = new VtuzxMap(otherOutDetailDoc);
            otherOutDetailMap.remove("unit");
            String _id = VtuzxUtil.removeString(otherOutDetailMap, IVtuzxConst.Key__id);
            String _createUserId = VtuzxUtil.removeString(otherOutDetailMap, "_createUserId");
            dataList.add(otherOutDetailMap.append("_id", _id).append("_createUserId", _createUserId));
        }
        for (VtuzxMap data: dataList) {
            String materialNo = VtuzxUtil.getString(data, "materialNo");
            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
            String fBaseUnitIdFName = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
            data.append("unit", fBaseUnitIdFName);
            data.append("count",String.format("%.2f",VtuzxUtil.getDouble(data,"count")));

        }
        //获取当前任务时间添加任务编号
        Date otherCreateTime = VtuzxUtil.getObject(otherOutDoc,"createTime");
        //把date转换成localdateTime获取当天开始时间和结束时间
        Instant instant = otherCreateTime.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        LocalDateTime startTime = localDateTime.with(LocalTime.MIN);
        LocalDateTime endTime = localDateTime.with(LocalTime.MAX);
        //再转化成String类型
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String localStartTime = startTime.format(formatter);
        String localEndTime = endTime.format(formatter);
        //根据任务编号的时间查询这一天的数据
        List<VtuzxMap> dayList = new ArrayList<>();
        Criteria cond = new Criteria();
        cond.and("apply").ne(true);
        cond.and("createTime").gte(VtuzxUtil.parseDate(localStartTime)).lte(VtuzxUtil.parseDate(localEndTime));
        Iterator<Document> otherInItr = otherOutDao.findList(cond, new Document("createTime", 1), 0, 0);
        while (otherInItr.hasNext()) {
            Document prdColDoc = otherInItr.next();
            VtuzxMap dayMap = new VtuzxMap(prdColDoc);
            dayList.add(dayMap);
        }
        //获取当前任务的序号
        int orderNum = 0;
        for (VtuzxMap map : dayList) {
            orderNum++;
            String taskBillNo = VtuzxUtil.getString(map, "billNo");
            if (billNo.equals(taskBillNo)) {
                break;
            }
        }
        header.append("orderNum",orderNum);
        return new VtuzxMap("header", header).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherOutBillDetailBox(ObjectId _userId, String _detailId) {
        Criteria cond = Criteria.where("_detailId").is(FastUtil.convertId(_detailId));
        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> otherOutDetailBoxItr = otherOutDetailBoxDao.findList(cond, null, 0, 0);
        while (otherOutDetailBoxItr.hasNext()) {
            Document otherOutDetailBoxDoc = otherOutDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(otherOutDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.remove("unit");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            Document detailDoc = otherOutDetailDao.findById(_detailId);
            String materialNo = VtuzxUtil.getString(detailDoc, "materialNo");
            boxMap.append("materialNo", materialNo);
            dataList.add(boxMap);
        }
        for (VtuzxMap data: dataList) {
            String materialNo = VtuzxUtil.getString(data, "materialNo");
            Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
            String fBaseUnitIdFName = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
            data.append("unit", fBaseUnitIdFName);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherOutBillApply(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String createUserName = VtuzxUtil.getString(param,"createUserName");
        List<String> createTime = VtuzxUtil.getObject(param,"createTime");
        Criteria cond = new Criteria();
        cond.and("apply").is(true);//判断是出库还是出库申请
        List<VtuzxMap> dataList = new ArrayList<>();
        if (!VtuzxUtil.isEmpty(batchNo)) {
            cond.and("batchNo").regex(batchNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(materialNo)) {
            cond.and("materialNo").regex(materialNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            cond.and("createUserName").regex(createUserName);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        VtuzxPage page = otherOutDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("materialNo",VtuzxUtil.getString(doc,"materialNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "createTime")))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("remark", VtuzxUtil.getString(doc, "remark"))
                .append("batchNo",VtuzxUtil.getString(doc,"batchNo"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherOutBillApplyDetail(ObjectId _userId,  String billNo) {
        Document otherOutDoc = otherOutDao.findOne(Criteria.where("billNo").is(billNo));
        String ckBillNo = VtuzxUtil.getString(otherOutDoc, "billNo");
        String remark = VtuzxUtil.getString(otherOutDoc,"remark");
        String createUserName = VtuzxUtil.getString(otherOutDoc, "createUserName");
        String batchNo = VtuzxUtil.getString(otherOutDoc, "batchNo");
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(otherOutDoc, "createTime"));
        String materialNo = VtuzxUtil.getString(otherOutDoc,"materialNo");
        String status = VtuzxUtil.getString(otherOutDoc,"status");
        double count = VtuzxUtil.getDouble(otherOutDoc, "count");
        VtuzxMap header = new VtuzxMap("billNo", ckBillNo)
                .append("createUserName", createUserName)
                .append("createTime", createTime)
                .append("count", count)
                .append("remark",remark)
                .append("materialNo",materialNo)
                .append("status",status)
                .append("batchNo",batchNo);
        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> otherOutDetailItr = otherOutDetailDao.findList(Criteria.where("billNo").is(billNo),null,0,0);
        while (otherOutDetailItr.hasNext()){
            Document otherOutDetailDoc = otherOutDetailItr.next();
            VtuzxMap otherMap = new VtuzxMap(otherOutDetailDoc);
            dataList.add(otherMap);
        }

        return new VtuzxMap("header", header).append("boxList",dataList);
    }

    @Override
    public VtuzxMap saveOtherOutApply(ObjectId _userId, String name, Map<String, Object> param) throws VtuzxException {
        List<Map<String,Object>> materialNoList = VtuzxUtil.getObject(param,"boxList");
        List<String> fNumberList = new ArrayList<>();
        for (Map<String,Object> materialDoc:materialNoList){
            String materialNo = VtuzxUtil.getString(materialDoc,"materialNo");
            fNumberList.add(materialNo);//存入传过来的物料编号
        }

        double count = VtuzxUtil.getDouble(param,"count");
        String remark = VtuzxUtil.getString(param,"remark");
        String billNo = IXqcConst.createBillNo(BillType.QTCK);
        Document otherDoc = new Document();
        otherDoc.append("count",count)
                .append("remark",remark)
                .append("billNo",billNo)
                .append("status",BillStatus.Audit.toString())
                .append("apply",true);
        ObjectId objectId = otherOutDao.insertBill(_userId, name, otherDoc);
        //查询物料规格和名字
        Iterator<Document> materialItr = materialDao.findList(Criteria.where("fNumber").in(fNumberList),null,0,0);
        List<Document> otherOutDetailList = new ArrayList<>();//往其他出库detail里添加的数据
        while (materialItr.hasNext()){
            Document materialDoc = materialItr.next();
            String materialNo = VtuzxUtil.getString(materialDoc,"fNumber");
            String materialName = VtuzxUtil.getString(materialDoc,"fName");
            String materialSpec = VtuzxUtil.getString(materialDoc,"fSpecification");
            String unit = VtuzxUtil.getString(materialDoc,"fBaseUnitIdFName");
            Document outDetailDoc = new Document();
            outDetailDoc.append("billNo",billNo)
                    .append("createTime",new Date())
                    .append("createUserName",name)
                    .append("_createUserId",_userId)
                    .append("materialNo",materialNo)
                    .append("materialName",materialName)
                    .append("unit",unit)
                    .append("materialSpec",materialSpec);
            otherOutDetailList.add(outDetailDoc);
        }
        //把数量和备注整理到otherOutDetailList
        for (Document otherOutDoc : otherOutDetailList){
            String fNumber = VtuzxUtil.getString(otherOutDoc,"materialNo");
            for (Map<String,Object> materialDoc : materialNoList){
                String materialNo = VtuzxUtil.getString(materialDoc,"materialNo");
                double fCount = VtuzxUtil.getDouble(materialDoc,"count");//每个物料的数量
                String comment = VtuzxUtil.getString(materialDoc,"comment");
                String batchNo = VtuzxUtil.getString(materialDoc,"batchNo");
                if (fNumber.equals(materialNo)){
                    otherOutDoc.append("count",fCount)
                            .append("batchNo",batchNo)
                            .append("comment",comment);
                }
            }
        }
        otherOutDetailDao.insertMany(otherOutDetailList);
        //传吉客云出库申请单

        Document storeDoc = storeTokenDao.findOne(Criteria.where("type").is("kingdee"));
        String outWarehouseCode = "XQWG00101";//仓库编码
        VtuzxMap stockParam = new VtuzxMap();//入库参数
        List<VtuzxMap> stockOutDetailViews = new ArrayList<>();//入库申请单明细
        for (Document doc : otherOutDetailList){//循环添加货品明细信息
            String materialNo = VtuzxUtil.getString(doc,"materialNo");
            String unit = VtuzxUtil.getString(doc,"unit");
            double otherCount = VtuzxUtil.getDouble(doc,"count");
            VtuzxMap goodsMap = new VtuzxMap();//getGoodsList方法返回值
            //需要先获取条码(skubarcode)
            VtuzxMap goodsParam = new VtuzxMap();
            goodsParam.append("pageIndex", 0)
                    .append("pageSize", 1)
                    .append("goodsNo", materialNo);
            try {
                goodsMap = iJiKeYunApiService.getGoodsList(storeDoc, goodsParam);
            } catch (Exception e) {
                throw new VtuzxException(e.getMessage());
            }
            LinkedHashMap result = VtuzxUtil.getObject(goodsMap, "result");
            LinkedHashMap data = VtuzxUtil.getObject((Map<String, Object>) result, "data");
            List<LinkedHashMap> goods = VtuzxUtil.getObject((Map<String, Object>) data, "goods");
            LinkedHashMap goodsResult = goods.get(0);
            String skuBarcode = VtuzxUtil.getString((Map<String, Object>) goodsResult, "skuBarcode");

            VtuzxMap map = new VtuzxMap();
            map.append("isSerial",0)
                    .append("skuBarcode",skuBarcode)
                    .append("skuCount",otherCount)
                    .append("unitName",unit)
                    .append("isCertified",1)
                    .append("relDetailId",billNo)
                    .append("isBatch",0);
            stockOutDetailViews.add(map);
        }
        stockParam.append("outWarehouseCode",outWarehouseCode)
                .append("outType", 204)
                .append("relDataId", billNo)//关联单据编号,可随机，保证不重复即可
                .append("applyDate", VtuzxUtil.formatYmdHmsF(new Date()))
                .append("operator", name)
                .append("source", "OPEN")
                .append("currencyRate",1)
                .append("memo","质检")
                .append("stockOutDetailViews", stockOutDetailViews);

        //创建出库单
        try {
            iJiKeYunApiService.createStock(storeDoc, stockParam);
        } catch (Exception e) {
            _logger.info(e.getMessage());
            throw new VtuzxException(e.getMessage());
        }

        return new VtuzxMap("billNo",billNo).append("status",BillStatus.Audit.toString());
    }

    //其他入库合-拆箱时选择对应的出库单号
    @Override
    public VtuzxMap getOtherOutBillPDA(ObjectId userId, Map<String, Object> param) {
        //获取当前时间往前7天的出库单号，
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH,-10);
        Date previousDate = calendar.getTime();

        Criteria cond = new Criteria();
        cond.and("status").is("audit").and("type").is("合-拆箱");
        cond.and("createTime").gte(previousDate).lte(date);

        List<Document> otherOutList = new ArrayList<>();
        Iterator<Document> otherOutItr = otherOutDao.findList(cond,new Document("createTime",-1),0,0);
        while (otherOutItr.hasNext()){
            Document otherOutDoc = otherOutItr.next();
            otherOutList.add(otherOutDoc);
        }

        return new VtuzxMap("data",otherOutList);
    }

    @Override
    public VtuzxMap updateOtherOutSeal(Serializable userId, String name, Map<String, Object> param) {
        String billNo = VtuzxUtil.getString(param, "billNo");
        otherOutDao.updateOneRedirect(Criteria.where("billNo").is(billNo), new Document("$set", new Document("isPrint", "seal")));
        return new VtuzxMap("isPrint", billNo);
    }

    /**
     * 下载其他出库详情
     * @param token
     * @param param
     * @return
     * @throws Exception
     */
    @Override
    public VtuzxDownloadBean downloadOtherOutDetail(VtuzxToken token, Map<String, Object> param) throws Exception {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String type = VtuzxUtil.getString(param,"type");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String isPrint = VtuzxUtil.getString(param, "isPrint");
        String taskBillNo = VtuzxUtil.getString(param, "taskBillNo");
        List<String> auditTime = VtuzxUtil.getObject(param, "auditTime");
        Criteria cond = new Criteria("apply").ne(true);
        cond.and("count").ne(0);//数量等于零的不显示
        List<VtuzxMap> dataList = new ArrayList<>();
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").regex(type);
        }
        if (!VtuzxUtil.isEmpty(taskBillNo)) {
            cond.and("taskBillNo").regex(taskBillNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(isPrint)) {
            cond.and("isPrint").is(isPrint);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(auditTime)) {
            cond.and("auditTime").gte(VtuzxUtil.parseDate(auditTime.get(0))).lte(VtuzxUtil.parseDate(auditTime.get(1) + " 23:59:59"));
        }


        List<String> billNoList = new ArrayList<>();//单据编号集合
        Map<String,Object> statusMap = new HashMap<>();//key;单据编号  value:状态
        Iterator<Document> purInItr = otherOutDao.findList(cond,  new Document("createTime",-1), 0, 0);
        while (purInItr.hasNext()) {
            Document purInDoc = purInItr.next();
            VtuzxMap purInMap = new VtuzxMap(purInDoc);
            purInMap.append("id", VtuzxUtil.removeString(purInMap, IVtuzxConst.Key__id));
            purInMap.append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(purInMap, "createTime")));
            dataList.add(purInMap);
            String otherBillNo = VtuzxUtil.getString(purInMap,"billNo");
            String status = VtuzxUtil.getString(purInMap,"status");
            if(!billNoList.contains(otherBillNo)){
                billNoList.add(otherBillNo);
            }
            if ("audit".equals(status)){
                statusMap.put(otherBillNo,"审核");
            } else {
                statusMap.put(otherBillNo,"保存");
            }
        }
        List<VtuzxMap> detailList = new ArrayList<>();//详情信息集合
        List<String> stockNoList = new ArrayList<>();//仓库集合
        //查询详情表数据
        Iterator<Document> otherOutDetailItr = otherOutDetailDao.findList(Criteria.where("billNo").in(billNoList), null, 0, 0);
        while (otherOutDetailItr.hasNext()){
            Document detailDoc = otherOutDetailItr.next();
            VtuzxMap detailMap = new VtuzxMap(detailDoc);
            String detailStockNo = VtuzxUtil.getString(detailMap,"stockNo");
            detailList.add(detailMap);
            if (!stockNoList.contains(detailStockNo)){
                stockNoList.add(detailStockNo);
            }
        }
        //查询仓库名称
        VtuzxMap stockMap = new VtuzxMap();
        Iterator<Document> stockItr = stockDao.findList(Criteria.where("fNumber").in(stockNoList), null, 0, 0);
        while (stockItr.hasNext()) {
            Document stock = stockItr.next();
            String stockNumber = VtuzxUtil.getString(stock, "fNumber");
            String stockName = VtuzxUtil.getString(stock, "fName");
            stockMap.append(stockNumber, stockName);
        }
        for (VtuzxMap otherDoc : detailList){
            String otherStockNo = VtuzxUtil.getString(otherDoc,"stockNo");
            String otherBillNo = VtuzxUtil.getString(otherDoc,"billNo");
            String stockName = VtuzxUtil.getString(stockMap,otherStockNo);//仓库名称
            String status = VtuzxUtil.getString(statusMap,otherBillNo);//状态
            otherDoc.append("stockName",stockName);
            otherDoc.append("status",status);
        }
        String timestamp = new SimpleDateFormat("yyMMddHHmmss").format(new Date());

        List<VtuzxExcelSheet> sheets = new ArrayList<>();
        VtuzxExcelSheet sheet0 = new VtuzxExcelSheet(0, "其他出库详情");
        int col = 0;
        int row = 0;
        VtuzxExcelRow header0 = new VtuzxExcelRow(row++, new VtuzxArrayList<>(
                new VtuzxExcelCell(col++, "状态"),
                new VtuzxExcelCell(col++, "出库单号"),
                new VtuzxExcelCell(col++, "创建时间"),
                new VtuzxExcelCell(col++, "仓库"),
                new VtuzxExcelCell(col++, "仓位"),
                new VtuzxExcelCell(col++, "物料编码"),
                new VtuzxExcelCell(col++, "物料名称"),
                new VtuzxExcelCell(col++, "物料规格"),
                new VtuzxExcelCell(col++, "单位"),
                new VtuzxExcelCell(col++, "批次"),
                new VtuzxExcelCell(col++, "箱数"),
                new VtuzxExcelCell(col, "重量")
        ));
        sheet0.addRow(header0);
        for (VtuzxMap detail : detailList) {
            col = 0;
            VtuzxExcelRow dataRow = new VtuzxExcelRow(row++, new VtuzxArrayList<>(
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "status")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "billNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.formatYmdHmF(VtuzxUtil.getObject(detail, "createTime"))),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "stockName")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "locationNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialName")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialSpec")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "unit")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "batchNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "boxCount")),
                    new VtuzxExcelCell(col++, new BigDecimal(VtuzxUtil.getString(detail, "count")).setScale(2, RoundingMode.HALF_UP).doubleValue())
            ));
            sheet0.addRow(dataRow);
        }

        sheet0.setColumnWidth(new VtuzxArrayList<>(
                new int[]{0, 200},
                new int[]{1, 200},
                new int[]{2, 200},
                new int[]{3, 300},
                new int[]{4, 200},
                new int[]{5, 200},
                new int[]{6, 150},
                new int[]{7, 150},
                new int[]{8, 80}
        ));

        sheets.add(sheet0);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        VtuzxExcel.write(stream, sheets);
        return new VtuzxDownloadBean("其他出库详情" + timestamp + ".xlsx", stream);
    }

}
